package com.gitee.wsl.security.encrypt.sample

import com.gitee.wsl.ext.base.circleIndex
import com.gitee.wsl.ext.base.propCase
import com.gitee.wsl.security.encrypt.Encrypt
import com.gitee.wsl.security.encrypt.StringToStringEncrypt
import com.ionspin.kotlin.bignum.integer.toBigInteger


/** y = ax + b x = (y- b) / a */
class Affine(val factor: Int, val bias: Int,val table: String = TABLE_A_Z) :StringToStringEncrypt{

    override fun encrypt(src: String): String =
        src.affineEncrypt(factor,bias,table)

    override fun decrypt(src: String): String =
        src.affineDecrypt(factor,bias,table)
}

fun Encrypt.Companion.affine(factor: Int, bias: Int, table: String = TABLE_A_Z) = Affine(factor,bias,table)


internal fun String.affineEncrypt(factor: Int, bias: Int, table: String = TABLE_A_Z) =
    map {
        when (it) {
            in table -> table[(factor * table.indexOf(it) + bias) % table.length].propCase(it)
            in TABLE_A_Z_LOWER ->
                TABLE_A_Z_LOWER[
                    (factor * TABLE_A_Z_LOWER.indexOf(it) + bias) % TABLE_A_Z_LOWER.length]
            else -> it
        }
    }
        .joinToString("")

internal fun String.affineDecrypt(factor: Int, bias: Int, table: String = TABLE_A_Z) =
    with(factor.toBigInteger().modInverse(table.length.toBigInteger()).intValue()) {
        map {
            when (it) {
                in table ->
                    table[(this * (table.indexOf(it) - bias)).circleIndex(table.length)]
                        .propCase(it)
                in TABLE_A_Z_LOWER ->
                    TABLE_A_Z_LOWER[
                        (this * (TABLE_A_Z_LOWER.indexOf(it) - bias)).circleIndex(
                            TABLE_A_Z_LOWER.length
                        )]
                else -> it
            }
        }
            .joinToString("")
    }
